#include "sqlLoop.h"
#include "sqliteCommon.h"
#include "pal/lane_cmd_parse.h"

static uv_async_t deviceSpeedAsync;
static uv_async_t asyncSql;

static uv_timer_t uploadPicTimer;
static uv_timer_t deleteSqlTimer;
static uv_timer_t resetIntervalTimer;

static void sqlExec(uv_async_t *handle);
static void handleSqlCmd(SqlAsyncCmd *cmd);

void dispatchSqlCmdExec()
{
    uv_async_send(&asyncSql);
}

void dispatchSpeedEvent(bool isSpeedLow)
{
    bool *tmp = (bool *)deviceSpeedAsync.data;
    *tmp = isSpeedLow;
    uv_async_send(&deviceSpeedAsync);
}

static void sqlExec(uv_async_t *handle)
{
    bool isHasSqlcmd = isSqlCmdQueueEmpty();

    Packet *packTmp = NULL;
    while (isHasSqlcmd != true)
    {
        packTmp = sqlDequeue();
        if (packTmp != NULL)
        {
            SqlAsyncCmd *cmd = (SqlAsyncCmd *)packTmp->pkt_data;
            handleSqlCmd(cmd);
            pkt_free(packTmp);
        }
        else
        {
            break;
        }
        isHasSqlcmd = isSqlCmdQueueEmpty();
    }
}

static void handleSqlCmd(SqlAsyncCmd *cmd)
{
    uint8_t *picName = cmd->picName;
    uint8_t *shotTimeBcd = cmd->shotTimeBcd;
    uint8_t *license = cmd->licese;
    uint8_t camId = cmd->camId;
    uint8_t fileNo = cmd->fileNo;
    uint8_t picType = cmd->picType;
    gps_t gps = cmd->gps;

    switch (cmd->cmdType)
    {
    case SQL_CMD_TYPE_ADD:
    {
        insertPicDb(picName, license, camId, fileNo, shotTimeBcd, gps, picType);
        break;
    }

    case SQL_CMD_TYPE_DEL:
    {
        deletePicRows();
        break;
    }

    case SQL_CMD_TYPE_UPDATE:
    {
        switch (cmd->updateType)
        {
        case SQL_CMD_UPDATE_UPLOAD_COL:
        {
            updatePicRowAfterUpload(picName);
            break;
        }

        case SQL_CMD_UPDATE_DELETE_COL:
        {
            updatePicRowAfterDelete(picName);
            break;
        }

        default:
            break;
        }
        break;
    }

    default:
        break;
    }
}

#define MAX_RETRY_SEND_COUNT 4
static bool isTimerStart = false;
static uint32_t selectPicAndAddSendQueue(uint8_t picType, uint8_t retryCount)
{
    SelectCamResult resBigPic = selectPicDb(picType, retryCount);

    for (size_t i = 0; i < resBigPic.len; i++)
    {
        CamDataStruct *tmp = &resBigPic.camArr[i];
        if (tmp->camData == CAM_NO_DATA)
        {
            continue;
        }

        // uint8_t picName[PIC_FILENAME_MAX_LEN] = {0};
        // genPicFileName(picName, tmp->uniqueTag, tmp->timeBcd, tmp->camId, tmp->picType);
        // LOG_INFO("数据库查询文件名结果：%s", picName);

        Packet *packTmp = PacketMalloc(sizeof(CamDataStruct));
        copy_packet(packTmp, sizeof(CamDataStruct), (uint8_t *)tmp);
        sql2SocketEnqueue(packTmp);
        dispatchSql2SocketEvent();

        if (retryCount >= 0)
        {
            uint8_t picName[PIC_FILENAME_MAX_LEN] = {0};
            genPicFileName(picName, tmp->uniqueTag, tmp->timeBcd, tmp->camId, tmp->picType);
            // LOG_INFO("数据库查询文件名结果：%s", picName);
            if ((retryCount + 1) != MAX_RETRY_SEND_COUNT)
            {
                updateRetryCountAfterSendToQueue(picName, retryCount + 1);
            }
        }
    }

    uint32_t len = resBigPic.len;
    free(resBigPic.camArr);
    return len;
}

static uint8_t retryCount = 0;
static void handleUploadPicFromSql(uv_timer_t *handle)
{
    uint8_t retryTime = retryCount % MAX_RETRY_SEND_COUNT;
    // 先传标定图片
    uint16_t calibrationSendLen = selectPicAndAddSendQueue(CALIBRATION_PIC_TYPE, retryTime);
    if (calibrationSendLen == 0)
    {
        // 没标定图片了传小图
        uint16_t smallSendLen = selectPicAndAddSendQueue(SMALL_PIC_TYPE, retryTime);
        if (smallSendLen == 0)
        {
            // 小图彻底传完，才开始传大图
            uint16_t bigSendLen = selectPicAndAddSendQueue(BIG_PIC_TYPE, retryTime);
            if (bigSendLen == 0)
            {
                retryCount++;
            }
        }
    }
}

#define SELECT_SQL_REPEAT_TIME_WITH_RESPONSE 20 * 1000
#define SELECT_SQL_REPEAT_TIME_WITH_NO_RESPONSE 60 * 1000
static void handlDeviceSpeedEvent(uv_async_t *handle)
{
    bool *isSpeedLow = (bool *)handle->data;
    if (*isSpeedLow == true)
    {
        retryCount = 0;
        uv_timer_start(&uploadPicTimer, handleUploadPicFromSql, 0, SELECT_SQL_REPEAT_TIME_WITH_RESPONSE);
    }
    else
    {
        uv_timer_stop(&uploadPicTimer);
    }
}

static void deleteSqlRecord(uv_timer_t *handle)
{
    deletePicRows();
}

static bool isRecvResponse = true;
void resetUploadTimerInterval()
{
    uint64_t oldRepeatTime = uv_timer_get_repeat(&uploadPicTimer);
    if (isRecvResponse == true)
    {
        if (oldRepeatTime != SELECT_SQL_REPEAT_TIME_WITH_RESPONSE)
        {
            // LOG_FATAL("旧时间：%ld", oldRepeatTime);
            // LOG_FATAL("置换5秒");
            uv_timer_set_repeat(&uploadPicTimer, SELECT_SQL_REPEAT_TIME_WITH_RESPONSE);
        }
        isRecvResponse = false;
    }
    else
    {
        if (oldRepeatTime != SELECT_SQL_REPEAT_TIME_WITH_NO_RESPONSE)
        {
            // LOG_FATAL("旧时间：%ld", oldRepeatTime);
            // LOG_FATAL("置换1分钟");
            uv_timer_set_repeat(&uploadPicTimer, SELECT_SQL_REPEAT_TIME_WITH_NO_RESPONSE);
        }
    }
}

void setRecvResponseTrue()
{
    isRecvResponse = true;
}

static bool is_sql_init_flag = false;
bool is_sql_function_init()
{
    return is_sql_init_flag;
}

void startSqlLoop()
{
    openPicDb();
    createPicDB();
    uv_async_init(getSqlLoop(), &asyncSql, sqlExec);

    deviceSpeedAsync.data = (bool *)malloc(sizeof(bool));
    uv_async_init(getSqlLoop(), &deviceSpeedAsync, handlDeviceSpeedEvent);

    uv_timer_init(getSqlLoop(), &uploadPicTimer);
    uv_timer_init(getSqlLoop(), &deleteSqlTimer);
    uv_timer_init(getSqlLoop(), &resetIntervalTimer);

    uv_timer_start(&deleteSqlTimer, deleteSqlRecord, 0, 5 * 1000);
    uv_timer_start(&resetIntervalTimer, resetUploadTimerInterval, SELECT_SQL_REPEAT_TIME_WITH_RESPONSE, SELECT_SQL_REPEAT_TIME_WITH_RESPONSE);
    is_sql_init_flag = true;
    uv_run(getSqlLoop(), UV_RUN_DEFAULT);
}
